package com.gui.snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;

public class GamePanel extends JPanel {
    private Snake snake;
    private boolean isStart;
    private boolean isFail;
    private Point food;
    private final Random random;
    private boolean lock;  // 如果你的按键过快，会出现能够将蛇身卡进去的情况，所以运算时需要锁一下

    public GamePanel() {
        init();
        this.setFocusable(true); // 获得焦点事件
        this.addKeyListener(new SnakeKeyListener()); // 获得键盘监听事件
        Timer timer = new Timer(100, new SnakeActionListener()); // 定时器
        timer.start();
        random = new Random();
    }

    public void init() {
        snake = new Snake();
        isStart = false;
        isFail = false;
        food = new Point(500, 100);
        lock = false;
    }

    private void randomFood(ArrayList<Point> points) {
        ArrayList<Point> validPoints = new ArrayList<>();
        for (int x = 25; x < 25 + 25 * 34; x += 25) {
            for (int y = 75; y < 75 + 25 * 24; y += 25) {
                boolean flag = false;
                for (Point point : points) {
                    if (point.equals(new Point(x, y))) {
                        flag = true;
                        points.remove(point);
                        break;
                    }
                }
                if (!flag) {
                    validPoints.add(new Point(x, y));
                }
            }
        }
        int ran = random.nextInt(validPoints.size());
        food = new Point(validPoints.get(ran));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // 清屏

        // 绘制静态的部分
        setBackground(Color.WHITE);
//        Data.header.paintIcon(this, g, 25, 11); // 头部广告栏
        g.fillRect(25, 75, 850, 600); // 游戏面板

        // 绘制食物
        Data.food.paintIcon(this, g, food.x, food.y);
        // 绘制蛇的身体
        boolean isHead = true;
        for (Point point : snake.getPoints()) {
            if (!isHead)
                Data.body.paintIcon(this, g, point.x, point.y);
            else {
                isHead = false;
                switch (snake.getDirection()) {
                    case UP:
                        Data.up.paintIcon(this, g, point.x, point.y);
                        break;
                    case DOWN:
                        Data.down.paintIcon(this, g, point.x, point.y);
                        break;
                    case LEFT:
                        Data.left.paintIcon(this, g, point.x, point.y);
                        break;
                    case RIGHT:
                        Data.right.paintIcon(this, g, point.x, point.y);
                        break;
                }
            }
        }

        // 游戏状态
        if (!isStart) {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Microsoft YaHei", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 300, 300);
        }
        if (isFail) {
            g.setColor(Color.RED);
            g.setFont(new Font("Microsoft YaHei", Font.BOLD, 40));
            g.drawString("游戏失败！按下空格重新开始", 150, 300);
        }
        g.setColor(Color.WHITE);
        g.setFont(new Font("Microsoft YaHei", Font.BOLD, 20));

        g.setColor(Color.black);
        g.drawString("长度：" + snake.getPoints().size(), 25, 50);
    }

    // 键盘监听器
    class SnakeKeyListener implements KeyListener {
        @Override
        public void keyTyped(KeyEvent e) {

        }

        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();
            switch (keyCode) {
                case KeyEvent.VK_SPACE:
                    isStart = !isStart;
                    if (isFail) {
                        isStart = true;
                        isFail = false;
                        init();
                    }
                    repaint();
                    break;
                case KeyEvent.VK_UP:
                    if (!lock && snake.getDirection() != Direction.DOWN) {
                        snake.setDirection(Direction.UP);
                        lock = true;
                    }
                    break;
                case KeyEvent.VK_DOWN:
                    if (!lock && snake.getDirection() != Direction.UP) {
                        snake.setDirection(Direction.DOWN);
                        lock = true;
                    }
                    break;
                case KeyEvent.VK_LEFT:
                    if (!lock && snake.getDirection() != Direction.RIGHT) {
                        snake.setDirection(Direction.LEFT);
                        lock = true;
                    }
                    break;
                case KeyEvent.VK_RIGHT:
                    if (!lock && snake.getDirection() != Direction.LEFT) {
                        snake.setDirection(Direction.RIGHT);
                        lock = true;
                    }
                    break;
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {

        }
    }

    // 计时器
    class SnakeActionListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            if (isStart && !isFail) {
                ArrayList<Point> points = snake.getPoints();
                Point head = new Point(points.get(0));
                boolean isGetFood = false;
                if (head.equals(food)) // 如果吃到食物
                    isGetFood = true;
                else
                    points.remove(points.size() - 1);  // 直接删除最后一个元素
                
                switch (snake.getDirection()) {
                    case UP:
                        head.y = head.y - 25 <= 50 ? 600 + 50 :head.y - 25;
                        break;
                    case DOWN:
                        head.y = head.y + 25 >= 625 + 50 ? 75 :head.y + 25;
                        break;
                    case LEFT:
                        head.x = head.x - 25 <= 0 ? 850 :head.x - 25;
                        break;
                    case RIGHT:
                        head.x = head.x + 25 >= 875 ? 25 :head.x + 25;
                        break;
                }
                for (Point point : points) {
                    if (point.equals(head)) {
                        isFail = true;
                        break;
                    }
                }
                points.add(0, head);
                snake.setPoints(points);
                if (isGetFood)
                    randomFood(new ArrayList<>(points));
                repaint();
            }
            lock = false;  // 每次运算完成解锁
        }
    }
}
